package org.reborn.engine.input

case class StateChangeEvent[T](oldState:T,newState:T)

/**
 * Keeps track of the state of a component. This could be boolean (buttons), or float (mouse movement change, analog stick)
 */
trait DeviceComponent[T] {
  val componentName:String;
  protected var state:T;

  protected def update(newState:T):Unit = {
	state = newState
  }
  
  /**
   * @return the current state of the component
   */
  def apply():T = state
  
  /**
   * @return the current state of the component
   */
  def value():T = state
  
}

/**
 * Adds State Change handler maintenance to a StatefulComponent
 */
trait ChangeStateHandlerSupport[T]{
  self: DeviceComponent[T] =>
  
  type StateChangeEventFunc=(StateChangeEvent[T]) => Unit;
  
  protected var changed:Boolean = false
  protected var stateChangeEventHandler: List[StateChangeEventFunc] = Nil;

  override def update(newState:T){
    changed = state != newState 
	for(handler <- stateChangeEventHandler; if changed){
	  handler(new StateChangeEvent(state,newState))	
	}
    
    state = newState
  }
  
  /**
   * @return whether or not the current polled state is different than the previous polled state 
   */
  def stateChanged:Boolean = changed
  
  /**
   * Registers a ChangeStateEventFunc handler that will fire if the component changes state  
   */
  def registerChangeHandler(handler:StateChangeEventFunc)= { 
	  stateChangeEventHandler = stateChangeEventHandler ::: List(handler) 
  }
  
  /**
   * UnRegisters a ChangeStateEventFunc handler  
   */
  def unRegisterChangeHandler(handler:StateChangeEventFunc)= { 
	  stateChangeEventHandler = stateChangeEventHandler.filterNot(_ == handler) 
  }
  
  /**
   * removes all ChangeStateEventFunc handlers  
   */
  def clearChangeHandlers()= { 
	  stateChangeEventHandler = Nil 
  }
}

/**
 * Component that only tracks boolean states (on or off) such as keys on a keyboard, or mouse buttons
 */
trait ButtonComponent extends DeviceComponent[Boolean] with ChangeStateHandlerSupport[Boolean]{
  def pressed():Boolean = state
}

/**
 * Component that tracks analog input such as a joystick or driving pedal
 */
trait AnalogButtonComponent extends DeviceComponent[Float]

/**
 * Component that tracks a change in position, such as the left-right or up-down movement of a mouse
 */
trait PositionChangeComponent extends DeviceComponent[Float]

object MissingButton extends ButtonComponent{
  val componentName = "Button Does Not Exist"
  protected var state = false
}

object MissingAnalogButton extends AnalogButtonComponent{
  val componentName = "Button Does Not Exist"
  protected var state = 0.0f
}

object MissingPositionChange extends PositionChangeComponent{
  val componentName = "Button Does Not Exist"
  protected var state = 0.0f
}